﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using log4net;

namespace DataLayer.SQL
{
    public class ParamBuilder
    {
        private static readonly ILog logger = LogManager.GetLogger(typeof(ParamBuilder));
        /// <summary>
        /// Crea un parametro sql
        /// </summary>
        /// <param name="name">Nombre del parametro</param>
        /// <param name="type">Tipo de dato o campo a almacenar en sql server</param>
        /// <param name="value">Valor a almacenar</param>
        /// <returns>Parametro SQL</returns>
        public SqlParameter CreateSQLParameter(string name, SqlDbType type, object value)
        {
            SqlParameter param = new SqlParameter(name, type);
            param.Direction = ParameterDirection.Input;
            param.Value = value;
            return param;
        }
        /// <summary>
        /// Crea una lista de parametros SQL a partir de las propiedades de un objeto
        /// </summary>
        /// <param name="entity">Objeto del que se obtendran los parámetros</param>
        /// <returns>Colección de parametros SQL</returns>
        public SqlParameter[] CreateSQLListParameters(object entity)
        {

            List<SqlParameter> list = new List<SqlParameter>();
            Type type = entity.GetType();
            PropertyInfo[] properties = type.GetProperties();

            object val = null;
            SqlParameter parameter = null;
            foreach (PropertyInfo item in properties)
            {
                val = item.GetValue(entity, null);
                // COMMENT: Se valida para evitar errores con tipos genericos y valores nulos 
                // en entidades, esto sirve para bindear únicamente tipos de datos primitivos.
                if (val != null && !item.PropertyType.IsGenericType)
                {
                    SqlDbType paramType = this.GetType(item.PropertyType.FullName);
                    parameter = this.CreateSQLParameter(item.Name, paramType, val);
                    list.Add(parameter);
                }
            }

            return list.ToArray();
        }
        /// <summary>
        /// Mapea el tipo de dato recibido a un tipo de dato SQL
        /// </summary>
        /// <param name="type">Cadena que contiene el nombre del tipo de dato</param>
        /// <returns>Enumeración que representa el tipo de dato de SQL</returns>
        private SqlDbType GetType(string type)
        {

                SqlDbType sqlType = SqlDbType.Char;
                switch (type)
                {
                    case "System.Int32":
                        sqlType = SqlDbType.Int;
                        break;
                    case "System.Guid":
                        sqlType = SqlDbType.UniqueIdentifier;
                        break;
                    case "System.String":
                        sqlType = SqlDbType.VarChar;
                        break;
                    case "System.Boolean":
                        sqlType = SqlDbType.Bit;
                        break;
                    case "System.DateTime":
                        sqlType = SqlDbType.DateTime;
                        break;
                    default:
                        Exception ex = new Exception(
                            String.Format("Se requiere mapear un objeto del tipo: {0}", 
                                sqlType.GetType().ToString()
                            )
                        );
                        logger.Error(ex.Message, ex);
                        throw ex;
                }
                return sqlType;
            }
    }
}
